package main.leetcode.offer.firstround.from03to50;

/**
 * 12.矩阵中的路径
 *
 * <p>请设计一个函数，用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始，每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格，那么该路径不能再次进入该格子。例如，在下面的3×4的矩阵中包含一条字符串“bfce”的路径（路径中的字母用加粗标出）。
 *
 * <p>[["a","b","c","e"],
 *
 * <p>["s","f","c","s"],
 *
 * <p>["a","d","e","e"]]
 *
 * <p>但矩阵中不包含字符串“abfb”的路径，因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后，路径不能再次进入这个格子。
 *
 * <p>
 *
 * <p>示例 1： 输入：board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
 * 输出：true
 *
 * <p>示例 2： 输入：board = [["a","b"],["c","d"]], word = "abcd" 输出：false
 *
 * <p>提示：1 <= board.length <= 200 1 <= board[i].length <= 200
 *
 * <p>来源：力扣（LeetCode） 链接：https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class ex12 {
    public static void main(String[] args) {
        char[][] board = {{'a', 'b', 'c', 'e'}, {'s', 'f', 'c', 's'}, {'a', 'd', 'e', 'e'}};
        System.out.println(new ex12().exist(board, "bfce"));
    }

    /**
     * 深度查找 + 回溯
     *
     * <p>时间复杂度 O(3^KMN)O(3 K MN) ：
     *
     * <p>最差情况下，需要遍历矩阵中长度为 KK 字符串的所有方案，时间复杂度为 O(3^K)O(3 K )；矩阵中共有 MNMN 个起点，时间复杂度为 O(MN)O(MN) 。
     *
     * <p>方案数计算： 设字符串长度为 KK ，搜索中每个字符有上、下、左、右四个方向可以选择，舍弃回头（上个字符）的方向，剩下 33 种选择， 因此方案数的复杂度为 O(3^K)O(3 K
     * )。
     *
     * <p>作者：jyd
     * 链接：https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof/solution/mian-shi-ti-12-ju-zhen-zhong-de-lu-jing-shen-du-yo/
     * 来源：力扣（LeetCode） 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     *
     * @param board
     * @param word
     * @return
     */
    public boolean exist(char[][] board, String word) {
        if (word.length() == 0) return true;
        for (int i = 0; i < board.length; i++)
            for (int j = 0; j < board[i].length; j++) if (dfs(board, i, j, word, 0)) return true;
        return false;
    }

    /**
     * 递归查找
     *
     * @param board 矩阵
     * @param i 开始横坐标
     * @param j 开始纵坐标
     * @param word 字符串
     * @param k 查找字符下标
     * @return 查找结果
     */
    private boolean dfs(char[][] board, int i, int j, String word, int k) {
        if (i > board.length - 1
                || i < 0
                || j > board[0].length - 1
                || j < 0
                || board[i][j] != word.charAt(k)) return false;
        if (k == word.length() - 1) return true; // 找完了
        char tmp = board[i][j];
        board[i][j] = '/'; // 防止该格子被再次访问
        boolean res =
                dfs(board, i + 1, j, word, k + 1) // 上
                        || dfs(board, i - 1, j, word, k + 1) // 下
                        || dfs(board, i, j - 1, word, k + 1) // 左
                        || dfs(board, i, j + 1, word, k + 1); // 右
        board[i][j] = tmp;
        return res;
    }
}
